from typing import Type, TypeVar, Generic, Optional, List, Any, Dict
from datetime import datetime, date
from sqlmodel import Session, select, func, and_, SQLModel
from fastapi import status
from app.models import User, PaginationRequest, PaginationInfo, PaginatedResponse

# 泛型类型变量
ModelType = TypeVar("ModelType", bound=SQLModel)
CreateSchemaType = TypeVar("CreateSchemaType", bound=SQLModel)
UpdateSchemaType = TypeVar("UpdateSchemaType", bound=SQLModel)


class BaseService(Generic[ModelType]):
    current_user: User 
    db: Session
    model: Type[ModelType]

    def __init__(self, db: Session, current_user: User, model: Type[ModelType] = None):
        self.current_user = current_user
        self.db = db
        self.model = model

    def build_date_filter(
        self, 
        model_field, 
        start_date: Optional[str] = None, 
        end_date: Optional[str] = None
    ) -> Optional[Any]:
        """构建日期范围筛选条件"""
        if not start_date and not end_date:
            return None
            
        if start_date and end_date:
            try:
                start = datetime.strptime(start_date, "%Y-%m-%d").date()
                end = datetime.strptime(end_date, "%Y-%m-%d").date()
                return func.date(model_field).between(start, end)
            except ValueError:
                raise ValueError("日期格式错误，请使用 yyyy-mm-dd 格式")
        elif start_date:
            try:
                start = datetime.strptime(start_date, "%Y-%m-%d").date()
                return func.date(model_field) >= start
            except ValueError:
                raise ValueError("开始日期格式错误，请使用 yyyy-mm-dd 格式")
        elif end_date:
            try:
                end = datetime.strptime(end_date, "%Y-%m-%d").date()
                return func.date(model_field) <= end
            except ValueError:
                raise ValueError("结束日期格式错误，请使用 yyyy-mm-dd 格式")
        return None

    def build_range_filter(
        self, 
        model_field, 
        min_val: Optional[float] = None, 
        max_val: Optional[float] = None
    ) -> Optional[Any]:
        """构建数值范围筛选条件"""
        if min_val is not None and max_val is not None:
            return model_field.between(min_val, max_val)
        elif min_val is not None:
            return model_field >= min_val
        elif max_val is not None:
            return model_field <= max_val
        return None

    def build_text_filter(
        self, 
        model_field, 
        text: Optional[str] = None, 
        exact_match: bool = False
    ) -> Optional[Any]:
        """构建文本筛选条件"""
        if text:
            if exact_match:
                return model_field == text
            else:
                return model_field.contains(text)
        return None

    async def get_paginated_results(
        self,
        conditions: List[Any] = None,
        order_by_field = None,
        descending: bool = True,
        pagination: PaginationRequest = None
    ) -> Dict[str, Any]:
        """
        通用的分页查询方法
        
        Args:
            conditions: 查询条件列表
            order_by_field: 排序字段
            descending: 是否降序
            pagination: 分页参数
            
        Returns:
            包含数据和分页信息的字典
        """
        if pagination is None:
            pagination = PaginationRequest()
            
        # 构建基础查询
        query = select(self.model)
        
        # 添加查询条件
        if conditions:
            query = query.where(and_(*conditions))
        
        # 查询总记录数
        count_query = select(func.count()).select_from(query.subquery())
        total_result = self.db.exec(count_query).first()
        total = total_result if total_result else 0
        
        if total == 0:
            return {
                "data": [],
                "total": 0,
                "total_pages": 0,
                "pagination": PaginationInfo(
                    current_page=pagination.current_page,
                    page_size=pagination.page_size,
                    total=0,
                    total_pages=0
                )
            }
        
        # 计算分页参数
        offset = (pagination.current_page - 1) * pagination.page_size
        total_pages = (total + pagination.page_size - 1) // pagination.page_size
        
        # 添加排序和分页
        if order_by_field:
            if descending:
                query = query.order_by(order_by_field.desc())
            else:
                query = query.order_by(order_by_field.asc())
        
        query = query.offset(offset).limit(pagination.page_size)
        
        # 执行查询
        result = self.db.exec(query).all()
        
        return {
            "data": result,
            "total": total,
            "total_pages": total_pages,
            "pagination": PaginationInfo(
                current_page=pagination.current_page,
                page_size=pagination.page_size,
                total=total,
                total_pages=total_pages
            )
        }

    def create_paginated_response(
        self,
        result_data: Dict[str, Any],
        response_class: Type[PaginatedResponse],
        message: str = "检索成功",
        code: int = 0
    ) -> PaginatedResponse:
        """
        创建分页响应
        
        Args:
            result_data: get_paginated_results返回的数据
            response_class: 响应类
            message: 响应消息
            code: 响应代码
            
        Returns:
            分页响应对象
        """
        return response_class(
            code=code,
            message=message,
            data=result_data["data"],
            pagination=result_data["pagination"]
        )

    def build_conditions_from_payload(
        self,
        payload: SQLModel,
        field_mappings: Dict[str, Dict[str, Any]]
    ) -> List[Any]:
        """
        根据字段映射配置循环构建查询条件
        
        Args:
            payload: 请求载荷对象
            field_mappings: 字段映射配置，格式为：
                {
                    "payload_field": {
                        "model_field": model_field,
                        "type": "text|range|date",
                        "exact_match": bool,  # 仅用于text类型
                        "start_field": str,   # 仅用于date类型，开始时间字段
                        "end_field": str      # 仅用于date类型，结束时间字段
                    }
                }
        
        Returns:
            查询条件列表
        """
        conditions = []
        
        for payload_field, config in field_mappings.items():
            # 获取模型字段名称
            field_name = config["field"]
            # 获取实际的模型字段对象
            model_field = getattr(self.model, field_name)
            field_type = config["type"]
            
            try:
                if field_type == "text":
                    # 获取载荷中的值
                    payload_value = getattr(payload, payload_field, None)
                    if payload_value is None:
                        continue
                    exact_match = config.get("exact_match", False)
                    filter_condition = self.build_text_filter(
                        model_field, payload_value, exact_match
                    )
                    if filter_condition is not None:
                        conditions.append(filter_condition)
                        
                elif field_type == "range":
                    # 处理范围类型
                    min_field = config.get("min_field")
                    max_field = config.get("max_field")
                    
                    if min_field and max_field:
                        # 双字段范围（如：home_initial_min, home_initial_max）
                        min_value = getattr(payload, min_field, None)
                        max_value = getattr(payload, max_field, None)
                        # 如果两个值都是None，则跳过
                        if min_value is None and max_value is None:
                            continue
                        filter_condition = self.build_range_filter(
                            model_field, min_value, max_value
                        )
                        if filter_condition is not None:
                            conditions.append(filter_condition)
                    else:
                        # 单字段范围
                        payload_value = getattr(payload, payload_field, None)
                        if payload_value is None:
                            continue
                        filter_condition = self.build_range_filter(
                            model_field, payload_value
                        )
                        if filter_condition is not None:
                            conditions.append(filter_condition)
                            
                elif field_type == "date":
                    # 日期筛选
                    start_field = config.get("start_field", payload_field + "_s")
                    end_field = config.get("end_field", payload_field + "_e")
                    start_value = getattr(payload, start_field, None)
                    end_value = getattr(payload, end_field, None)
                    
                    if start_value is not None or end_value is not None:
                        filter_condition = self.build_date_filter(
                            model_field, start_value, end_value
                        )
                        if filter_condition is not None:
                            conditions.append(filter_condition)
                            
            except ValueError as e:
                # 日期格式错误等，直接抛出异常让上层处理
                raise e
                
        return conditions


class QueryService(BaseService):
    """专门用于查询的服务类，不继承泛型模型"""
    
    def __init__(self, db: Session, current_user: User):
        super().__init__(db, current_user)
